﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class FM_Note : FM_BaseNote
{
    public bool beam;
    public float ys, startX;
    public float StemTopY = 0f;
    public bool isTieStart = false;//延音的开始
    public bool isTieEnd = false;//延音的结束
    public FM_ClefValue clef;
    public FM_Note(FM_Score Score, int Note, int Octave, FM_ClefValue clef, /*FM_Accidental*/int Accidental, FM_DurationValue Duration, int voice) : base(FM_NoteType.NOTE, Score.ScoreBase)
    {
        this.note = Note;
        this.accidental = Accidental;
        this.octave = Octave;
        this.duration = Duration;
        this.stem = true;
        this.stem_up = true;
        this.beam = false;
        this.voice = voice;
        this.clef = clef;
    }

    public FM_Note(FM_ScoreBase Score, int Note, int Octave, FM_ClefValue clef, int Accidental, FM_DurationValue Duration, int voice) : base(FM_NoteType.NOTE, Score)
    {
        this.note = Note;
        this.accidental = Accidental;
        this.octave = Octave;
        this.duration = Duration;
        this.stem = true;
        this.stem_up = true;
        this.beam = false;
        this.voice = voice;
        this.clef = clef;
    }

    public FM_Note(FM_ScoreBase Score, int Note, int Octave, FM_ClefValue clef, int Accidental, FM_DurationValue Duration, int voice, Color Color) : base(FM_NoteType.NOTE, Score)
    {
        this.note = Note;
        this.accidental = Accidental;
        this.octave = Octave;
        this.duration = Duration;
        this.stem = true;
        this.stem_up = true;
        this.beam = false;
        this.tuplet = false;
        this.color = Color;
        this.voice = voice;
        this.clef = clef;
    }

    public FM_Note(FM_Score Score, int Note, int Octave, FM_ClefValue clef, int Accidental, FM_DurationValue Duration, int voice, Color Color) : base(FM_NoteType.NOTE, Score.ScoreBase)
    {
        this.note = Note;
        this.accidental = Accidental;
        this.octave = Octave;
        this.duration = Duration;
        this.stem = true;
        this.stem_up = true;
        this.beam = false;
        this.tuplet = false;
        this.color = Color;
        this.voice = voice;
        this.clef = clef;
    }

    public FM_Note(FM_ScoreBase Score, int Note, int Octave, FM_ClefValue clef, int Accidental, FM_DurationValue Duration, int voice, bool StemUp) : base(FM_NoteType.NOTE, Score)
    {
        this.note = Note;
        this.accidental = Accidental;
        this.octave = Octave;
        this.duration = Duration;
        this.stem = true;
        this.stem_up = StemUp;
        this.beam = false;
        this.tuplet = false;
        this.voice = voice;
        this.clef = clef;
    }

    public FM_Note(FM_Score Score, int Note, int Octave, FM_ClefValue clef, int Accidental, FM_DurationValue Duration, int voice, bool StemUp) : base(FM_NoteType.NOTE, Score.ScoreBase)
    {
        this.note = Note;
        this.accidental = Accidental;
        this.octave = Octave;
        this.duration = Duration;
        this.stem = true;
        this.stem_up = StemUp;
        this.beam = false;
        this.tuplet = false;
        this.voice = voice;
        this.clef = clef;
    }

    public FM_Note(FM_ScoreBase Score, int Note, int Octave, FM_ClefValue clef, int Accidental, FM_DurationValue Duration, int voice, bool StemUp, Color Color) : base(FM_NoteType.NOTE, Score)
    {
        this.note = Note;
        this.accidental = Accidental;
        this.octave = Octave;
        this.duration = Duration;
        this.stem = true;
        this.stem_up = StemUp;
        this.beam = false;
        this.tuplet = false;
        this.color = Color;
        this.voice = voice;
        this.clef = clef;
    }

    public FM_Note(FM_Score Score, int Note, int Octave, FM_ClefValue clef, int Accidental, FM_DurationValue Duration, int voice, bool StemUp, Color Color) : base(FM_NoteType.NOTE, Score.ScoreBase)
    {
        this.note = Note;
        this.accidental = Accidental;
        this.octave = Octave;
        this.duration = Duration;
        this.stem = true;
        this.stem_up = StemUp;
        this.beam = false;
        this.tuplet = false;
        this.color = Color;
        this.voice = voice;
        this.clef = clef;
    }

    public int GetOctave()
    {
        return octave;
    }

    void SetOctave(int o)
    {
        octave = o;
    }

    public override float GetDisplacement()
    {
        float offset = 0.0f;
        if (note == FM_NoteValue.DO) offset = 0.0f;
        if (note == FM_NoteValue.RE) offset = -0.5f;
        if (note == FM_NoteValue.MI) offset = -1.0f;
        if (note == FM_NoteValue.FA) offset = -1.5f;
        if (note == FM_NoteValue.SOL) offset = -2.0f;
        if (note == FM_NoteValue.LA) offset = -2.5f;
        if (note == FM_NoteValue.SI) offset = -3.0f;

        if (clef == FM_ClefValue.TREBLE)
        {
            offset = offset + 5.0f + 3.5f * (4 - octave);
            return offset;
        }
        if (clef == FM_ClefValue.BASS)
        {
            offset = offset + 6.0f + 3.5f * (2 - octave);
            return offset;
        }
        return 0.0f;
    }

    string AsStringAccidental()
    {
        string s1 = "";
        string b = "";
        string e = "";
        int accidental = this.accidental;
        if (accidental > 100)
        {
            b = FM_Const.ParenthesisLeft;
            e = FM_Const.ParenthesisRight;
            accidental = accidental - 100;
        }
        if (accidental == FM_Accidental.Natural) s1 = b + FM_Const.Natural + e + " ";
        if (accidental == FM_Accidental.Flat) s1 = b + FM_Const.Flat + e + " ";
        if (accidental == FM_Accidental.Sharp) s1 = b + FM_Const.Sharp + e + " ";
        if (accidental == FM_Accidental.DoubleSharp) s1 = b + FM_Const.DoubleSharp + e + " ";
        if (accidental == FM_Accidental.DoubleFlat) s1 = b + FM_Const.DoubleFlat + e + " ";
        if (accidental == FM_Accidental.TripleSharp) s1 = b + FM_Const.Sharp + " " + FM_Const.DoubleSharp + e + " ";
        if (accidental == FM_Accidental.TripleFlat) s1 = b + FM_Const.TripleFlat + e + " ";
        return s1;
    }

    string AsStringDot()
    {
        string s2 = "";
        if ((int)duration > 50) s2 = " " + FM_Const.Dot;
        return s2;
    }

    string AsStringNote()
    {
        return AsStringNote(stem);
    }

    string AsStringNote(bool stem)
    {
        int durationInt = (int)duration;

        if (durationInt == 1 || durationInt == 51) return FM_Const._1Note;
        if (stem && !beam)
        {
            if (stem_up)
            {
                if (durationInt == 2 || durationInt == 52) return FM_Const._2Note_up;
                if (durationInt == 4 || durationInt == 54) return FM_Const._4Note_up;
                if (durationInt == 8 || durationInt == 58) return FM_Const._8Note_up;
                if (durationInt == 16 || durationInt == 66) return FM_Const._16Note_up;
                if (durationInt == 32 || durationInt == 82) return FM_Const._32Note_up;
            }
            else
            {
                if (durationInt == 2 || durationInt == 52) return FM_Const._2Note_down;
                if (durationInt == 4 || durationInt == 54) return FM_Const._4Note_down;
                if (durationInt == 8 || durationInt == 58) return FM_Const._8Note_down;
                if (durationInt == 16 || durationInt == 66) return FM_Const._16Note_down;
                if (durationInt == 32 || durationInt == 82) return FM_Const._32Note_down;
            }
        }
        else
        {
            if (durationInt == 2 || durationInt == 52) return FM_Const.EmptyNote;
            return FM_Const.FillNote;
        }
        return "";
    }

    public override string AsString()
    {
        return AsStringAccidental() + AsStringNote() + AsStringDot();
    }

    public override float WidthAccidental()
    {
        if (score.score == null) return 0;
        FM_Const.AdjustFont(score.score, FM_Const.Sharp, 2);
        return score.score.Font.MeasureText(AsStringAccidental());
    }

    public override float WidthNoteNoStem()
    {
        if (score.score == null) return 0;
        FM_Const.AdjustFont(score.score, AsStringNote(false), 1);
        return score.score.Font.MeasureText(AsStringNote(false));
    }

    public override float WidthNote()
    {
        if (score.score == null) return 0;
        FM_Const.AdjustFont(score.score, AsStringNote(false), 1);
        return score.score.Font.MeasureText(AsStringNote(stem));
    }

    public override float WidthDot()
    {
        if (score.score == null) return 0;
        FM_Const.AdjustFont(score.score, FM_Const.Sharp, 2);
        return score.score.Font.MeasureText(AsStringDot());
    }

    public float Height(bool all)
    {
        if (score.score == null) return 0;
        FM_Const.AdjustFont(score.score, AsStringNote(false), 1);
        bool tmp_beam = beam;
        if (all) beam = false;
        Rect bounds = new Rect();
        string s = AsStringNote();
        score.score.Font.GetTextBounds(s, 0, s.Length, bounds);
        beam = tmp_beam;
        return bounds.height;//.Height();
    }

    public override void DrawNote(ScoreCanvas canvas)
    {
        if (score.score == null) return;
        if (!IsBlurred() && !IsVisible()) return;
        base.DrawNote(canvas);

        score.score.Font.Color = score.score.GetStaveLineColor();
        //if (IsBlurred())
        //    score.score.Font.MaskFilter = new BlurMaskFilter(30, BlurMaskFilter.Blur.Normal);
        //else score.score.Font.MaskFilter = null;
        ys = StartY1;
        startX = StartX;
        float ly;
        float dy;
        bool l = false;
        float offset = GetDisplacement();
        if (offset >= 5.0f || offset < 0.0f) l = true;
        dy = StartY1 + offset * score.score.GetDistanceBetweenStaveLines();

        float width_accidental = WidthAccidental();
        float widthNoteNoStem = WidthNoteNoStem();
        if (l)
        {
            if (offset >= 5.0f)
                for (int i = 5; i <= offset; i++)
                {
                    ly = StartY1 + i * score.score.GetDistanceBetweenStaveLines();
                    float tX = StartX + paddingLeft + width_accidental + paddingNote - score.score.GetDistanceBetweenStaveLines() / 3;
                    float tXe = StartX + paddingLeft + width_accidental + paddingNote + widthNoteNoStem + score.score.GetDistanceBetweenStaveLines() / 3;
                    float tY = ly - FM_Const.dpTOpx(0.25f);
                    float tYe = ly + FM_Const.dpTOpx(0.25f);
                    canvas.DrawRect(tX, tY, tXe, tYe, score.score.Font);
                }
            if (offset < 0.0f)
                for (int i = -1; i >= offset; i--)
                {
                    ly = StartY1 + i * score.score.GetDistanceBetweenStaveLines();
                    float tX = StartX + paddingLeft + width_accidental + paddingNote - score.score.GetDistanceBetweenStaveLines() / 3;
                    float tXe = StartX + paddingLeft + width_accidental + paddingNote + widthNoteNoStem + score.score.GetDistanceBetweenStaveLines() / 3;
                    float tY = ly - FM_Const.dpTOpx(0.25f);
                    float tYe = ly + FM_Const.dpTOpx( 0.25f);
                    canvas.DrawRect(tX, tY, tXe, tYe, score.score.Font);

                    //Debug.LogError($"tY:{tY}  tYe:{tYe}");
                }
        }
        score.score.Font.Color = score.score.GetColor();
        score.score.Font.Color = color;

        FM_Const.AdjustFont(score.score, FM_Const.Sharp, 2);
        float offsetX = 4;
        canvas.DrawText(AsStringAccidental(), StartX + paddingLeft + offsetX + 7, dy, score.score.Font);
        FM_Const.AdjustFont(score.score, FM_Const.EmptyNote, 1);
        canvas.DrawText(AsStringNote(), StartX + paddingLeft + width_accidental + paddingNote + offsetX, dy, score.score.Font);

        if ((int)duration > 50)
        {
            float adjustDotY = 0;
            if (Math.Abs(offset) - Math.Floor(Math.Abs(offset)) < 0.1)
            {
                if (stem_up) adjustDotY = -score.score.GetDistanceBetweenStaveLines() * 0.2f;
                else adjustDotY = +score.score.GetDistanceBetweenStaveLines() * 0.2f;
            }
            adjustDotY += displacedot * score.score.GetDistanceBetweenStaveLines() * 0.25f;

            canvas.DrawText(AsStringDot(), StartX + paddingLeft + width_accidental + paddingNote + widthNoteNoStem + paddingDot + offsetX, dy + adjustDotY, score.score.Font);
        }
        score.score.Font.Color = score.score.GetColor();
        //score.score.Font.MaskFilter = null;
    }

    public override float Left()
    {
        return StartX + paddingLeft;
    }

    public override float Bottom()
    {
        if (score.score == null) return 0;
        float offset = GetDisplacement();
        float dy = StartY1 + offset * score.score.GetDistanceBetweenStaveLines();
        if (stem_up)
        {
            return dy + 0.5f * score.score.GetDistanceBetweenStaveLines();
        }
        else
        {
            return dy - 0.5f * score.score.GetDistanceBetweenStaveLines();
        }
    }
    public override float Right()
    {
        if (score.score == null) return 0;
        float w1 = StartX + paddingLeft + WidthAccidental() + paddingNote + WidthNoteNoStem() + paddingDot + WidthDot();
        float w2 = StartX + paddingLeft + WidthAccidental() + paddingNote + WidthNote();
        return Mathf.Max(w1, w2);
    }
    public override float Top()
    {
        if (score.score == null) return 0;
        float by = Bottom();
        if (stem_up)
        {
            return by - Height(stem);
        }
        else
        {
            return by + Height(stem);
        }
    }

    //[FM_NoteValue]
    public int GetNote()
    {
        return note;
    }
}
